package cn.lili.modules.system.aspect.interceptor;

import cn.lili.common.security.AuthUser;
import cn.lili.common.security.context.UserContext;
import cn.lili.common.security.enums.UserEnums;
import cn.lili.common.utils.IpHelper;
import cn.lili.common.utils.IpUtils;
import cn.lili.common.utils.SpelUtil;
import cn.lili.common.utils.ThreadPoolUtil;
import cn.lili.modules.permission.entity.vo.SystemLogVO;
import cn.lili.modules.system.aspect.annotation.SystemLogPoint;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;

/**
 * Spring AOP实现日志管理
 *
 * @author Chopper
 */
@Aspect
@Component
@Slf4j
public class SystemLogAspect {

//    @Autowired
//    private SystemLogService systemLogService;

    @Autowired
    private HttpServletRequest request;
    @Autowired
    private IpHelper ipHelper;

    @Pointcut("@annotation(cn.lili.modules.system.aspect.annotation.SystemLogPoint)")
    public void controllerAspect() {}

    @Around("controllerAspect()")
    public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();
        Object result = null;
        try {
            result = joinPoint.proceed();
            return result;
        } finally {
            try {
                long usedTime = System.currentTimeMillis() - startTime;
                buildSystemLog(joinPoint, result, usedTime);
            } catch (Exception e) {
                log.error("系统日志保存异常", e);
            }
        }
    }

    private void buildSystemLog(JoinPoint joinPoint, Object rvt, long usedTime) {
        Map map = spelFormat(joinPoint, rvt);
        String description = map.get("description").toString();
        String customerLog = map.get("customerLog").toString();

        Map<String, String[]> logParams = request.getParameterMap();
        AuthUser authUser = UserContext.getCurrentUser();
        SystemLogVO systemLogVO = new SystemLogVO();

        if (authUser == null) {
            systemLogVO.setStoreId(-2L);
            systemLogVO.setUsername("游客");
        } else {
            systemLogVO.setStoreId(authUser.getRole().equals(UserEnums.STORE) ?
                    Long.parseLong(authUser.getStoreId()) : -1);
            systemLogVO.setUsername(authUser.getUsername());
        }

        // 设置日志属性（与原先after()方法中的相同）
        systemLogVO.setName(description);
        systemLogVO.setRequestUrl(request.getRequestURI());
        systemLogVO.setRequestType(request.getMethod());
        systemLogVO.setMapToParams(logParams);
        systemLogVO.setIp(IpUtils.getIpAddress(request));
        systemLogVO.setIpInfo(ipHelper.getIpCity(request));
        systemLogVO.setCustomerLog(customerLog);
        systemLogVO.setCostTime((int) usedTime); // 直接使用传入的耗时

        // 保存日志（原异步保存逻辑）
        ThreadPoolUtil.getPool().execute(() -> {
            try {
                // 实际保存日志操作
                // systemLogService.saveLog(systemLogVO);
            } catch (Exception e) {
                log.error("系统日志保存异常,内容{}：", systemLogVO, e);
            }
        });
    }

    /**
     * 获取注解中对方法的描述信息 用于Controller层注解
     *
     * @param joinPoint 切点
     * @return 方法描述
     * @throws Exception
     */
    private static Map<String, String> spelFormat(JoinPoint joinPoint, Object rvt) {

        Map<String, String> result = new HashMap<>(2);
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        SystemLogPoint systemLogPoint = signature.getMethod().getAnnotation(SystemLogPoint.class);
        String description = systemLogPoint.description();
        String customerLog = SpelUtil.compileParams(joinPoint, rvt, systemLogPoint.customerLog());

        result.put("description", description);
        result.put("customerLog", customerLog);
        return result;
    }

}
